package routes

import (
	"encoding/json"
	"github.com/gin-gonic/gin"
	"go.uber.org/zap"
	"net/http"
	"runtime"
	"strings"
	"sync"
	"virus-proxy/internal/errno"
	"virus-proxy/internal/mount"
	"virus-proxy/internal/vendor_api/client"
)

// 使用锁保护响应写入，确保并发安全
var globalMutex = sync.Mutex{}

const vendor = "QiAnXin"

func ListMountPoint() func(c *gin.Context) {
	return func(c *gin.Context) {
		_ = mount.UpdateMount()
		if runtime.GOOS == "windows" {
			c.JSON(http.StatusOK, mount.MountSliceIns.Drives)
		} else {
			c.JSON(http.StatusOK, mount.MountSliceIns.DriversMap)
		}
	}
}

// @Summary	挂载cifs共享
// @Produce	json
// @Param		fsPath		query		string		true	"共享路径"	maxlength(100)
// @Param		userName	query		string		false	"用户名"
// @Param		passwd		query		string		false	"密码"
// @Success	0			{object}	errno.err	"成功"
// @Failure	10002		{object}	errno.err	"参数有误"
// @Failure	10004		{object}	errno.err	"挂载失败"
// @Router		/mountPoint [post]
func MountPoint() func(c *gin.Context) {
	return func(c *gin.Context) {
		var param struct {
			HostIp     string `json:"hostIp,omitempty"`
			FsPath     string `json:"fsPath"`
			MountPoint string `json:"mountPoint,omitempty"`
			UserName   string `json:"userName,omitempty"`
			Passwd     string `json:"passwd,omitempty"`
		}
		if err := c.ShouldBindJSON(&param); err != nil {
			c.JSON(http.StatusOK, errno.ErrParam.WithData(err.Error()))
			return
		}
		// 先更新全局MountArray
		_ = mount.UpdateMount()
		// 先查询本地对应的主机有没有相应的挂载点
		mounted, err := mount.IsMounted(c.ClientIP() + param.FsPath)
		if err != nil {
			c.JSON(http.StatusOK, errno.ErrMount.WithData(zap.String("Failed to query mounted filesystem. ", err.Error())))
			return
		}
		// 存在挂载点
		if mounted {
			// 判断挂载点是否正常
			if err = mount.CheckMountHealth(param.FsPath, c.ClientIP()); err == nil {
				c.JSON(http.StatusOK, errno.OK.WithData("//"+c.ClientIP()+param.FsPath+" already mounted"))
				return
			}
			// 不正常进行卸载
			err = mount.UnMountFS(param.FsPath, c.ClientIP())
			if err != nil {
				c.JSON(http.StatusOK, errno.ErrUnMount.WithData(zap.String("Failed to unmount filesystem:"+"//"+c.ClientIP()+param.FsPath, err.Error())))
				return
			}
		}
		// 挂载文件系统
		err = mount.FSMount("//"+c.ClientIP()+param.FsPath, param.UserName, param.Passwd)
		if err != nil {
			c.JSON(http.StatusOK, errno.ErrMount.WithData(zap.String("Failed to mount filesystem:"+"//"+c.ClientIP()+param.FsPath, err.Error())))
			return
		}
		c.JSON(http.StatusOK, errno.OK.WithData(zap.String("//"+c.ClientIP()+param.FsPath, "mount filesystem success")))
	}
}

// @Summary	卸载cifs共享
// @Produce	json
// @Param		fsPath	query		string		true	"共享路径"	maxlength(100)
// @Success	0		{object}	errno.err	"成功"
// @Failure	10002	{object}	errno.err	"参数有误"
// @Failure	10004	{object}	errno.err	"卸载失败"
// @Router		/unMount [post]
func UnMountPoint() func(c *gin.Context) {
	return func(c *gin.Context) {
		var param struct {
			FsPath string `json:"fsPath"`
		}
		if err := c.ShouldBindJSON(&param); err != nil {
			c.JSON(http.StatusOK, errno.ErrParam.WithData(err.Error()))
			return
		}
		// 先更新全局MountArray
		_ = mount.UpdateMount()
		// 卸载文件系统
		err := mount.UnMountFS(param.FsPath, c.ClientIP())
		if err != nil {
			c.JSON(http.StatusOK, errno.ErrUnMount.WithData(zap.String("Failed to unmount filesystem:"+"//"+c.ClientIP()+param.FsPath, err.Error())))
			return
		}
		c.JSON(http.StatusOK, errno.OK.WithData(zap.String("unmount filesystem success.", "//"+c.ClientIP()+param.FsPath)))
	}
}

// @Summary	调用火绒/奇安信扫描任务
// @Produce	json
// @Param		scanList	query		[]string	true	"扫描文件列表(如果厂商为奇安信,则只会扫描数组首个元素)"	maxlength(100)
// @Param		security	query		string		true	"扫描厂商"							maxlength(100)
// @Success	0			{object}	errno.err	"成功"
// @Failure	10002		{object}	errno.err	"参数有误"
// @Failure	10003		{object}	errno.err	"调用任务失败"
// @Router		/scan [post]
func ScanTask(proxy *client.Proxy) func(c *gin.Context) {
	return func(c *gin.Context) {
		var param struct {
			ScanList []string `json:"scanList,omitempty"`
			Security string   `json:"security"`
			//ScanFile string   `json:"scanFile,omitempty"`
		}
		if err := c.ShouldBindJSON(&param); err != nil {
			c.JSON(http.StatusOK, errno.ErrParam.WithData(err.Error()))
			return
		}
		if param.Security != vendor {
			c.JSON(http.StatusOK, errno.ErrFaultSecurity)
			return
		}
		if len(param.ScanList) == 0 {
			c.JSON(http.StatusOK, errno.ErrParam.WithData("scanList empty"))
			return
		}
		switch param.Security {
		case "HuoRong":
			body, err := proxy.CallKillTask(param.ScanList, c.ClientIP())
			if err != nil {
				c.JSON(http.StatusOK, errno.ErrCallTask.WithData(err.Error()))
				return
			}
			// 将 body 转为 JSON 格式
			var jsonData map[string]interface{} // 定义一个 map 来存储解析后的 JSON 数据
			_ = json.Unmarshal(body, &jsonData)
			// 返回 JSON 数据
			c.JSON(http.StatusOK, jsonData)
			//TODO 读取本机扫描日志结果返回给Nas,但火绒扫描完成后没有通知用户的机制,所以不知道什么时候开始扫描日志

		case "QiAnXin":
			QAX := client.NewQAX()
			body, err := QAX.CallKillTask(param.ScanList[0], c.ClientIP())
			if err != nil {
				c.JSON(http.StatusOK, errno.ErrCallTask.WithData(zap.String(param.ScanList[0], string(body))))
				return
			}
			c.JSON(http.StatusOK, errno.OK.WithData(map[string]string{"file": param.ScanList[0], "result": string(body)}))
		default:
			c.JSON(http.StatusOK, errno.ErrSecurity)
		}
	}
}

// @Summary	调用实时扫描任务
// @Produce	json
// @Param		scanList	query		[]string	true	"扫描文件列表(如果厂商为奇安信,则只会扫描数组首个元素)"	maxlength(100)
// @Param		security	query		string		true	"扫描厂商"							maxlength(100)
// @Success	0			{object}	errno.err	"成功"
// @Failure	10002		{object}	errno.err	"参数有误"
// @Failure	10003		{object}	errno.err	"调用任务失败"
// @Router		/realTimeScan [post]
func ScanRealTimeTask(proxy *client.Proxy) func(c *gin.Context) {
	return func(c *gin.Context) {
		var param struct {
			ScanList []string `json:"scanList"`
			Security string   `json:"security"`
			//ScanFile string   `json:"scanFile,omitempty"`
		}
		if err := c.ShouldBindJSON(&param); err != nil {
			c.JSON(http.StatusOK, errno.ErrParam.WithData(err.Error()))
			return
		}
		if param.Security != vendor {
			c.JSON(http.StatusOK, errno.ErrFaultSecurity)
			return
		}
		// 获取根目录用于挂载
		FsPath := "/" + strings.SplitN(param.ScanList[0], "/", 3)[1]
		// 先更新全局MountArray
		_ = mount.UpdateMount()
		// 先查询本地对应的主机有没有相应的挂载点
		mounted, err := mount.IsMounted(c.ClientIP() + FsPath)
		if err != nil {
			c.JSON(http.StatusOK, errno.ErrMount.WithData(zap.String("Failed to query mounted filesystem. ", err.Error())))
			return
		}
		// 存在挂载点
		if mounted {
			// 判断挂载点是否正常
			if err = mount.CheckMountHealth(FsPath, c.ClientIP()); err != nil {
				// 不正常进行卸载
				err = mount.UnMountFS(FsPath, c.ClientIP())
				if err != nil {
					c.JSON(http.StatusOK, errno.ErrUnMount.WithData(zap.String("Filesystem is not healthy,failed to unmount filesystem:"+"//"+c.ClientIP()+FsPath, err.Error())))
					return
				}
				// 挂载文件系统
				err = mount.FSMount("//"+c.ClientIP()+FsPath, "", "")
				if err != nil {
					c.JSON(http.StatusOK, errno.ErrMount.WithData(zap.String("Failed to mount filesystem:"+"//"+c.ClientIP()+FsPath, err.Error())))
					return
				}
			}
		} else {
			// 挂载文件系统
			err = mount.FSMount("//"+c.ClientIP()+FsPath, "", "")
			if err != nil {
				c.JSON(http.StatusOK, errno.ErrMount.WithData(zap.String("Failed to mount filesystem:"+"//"+c.ClientIP()+FsPath, err.Error())))
				return
			}
		}
		switch param.Security {
		case "QiAnXin":
			QAX := client.NewQAX()
			body, err := QAX.CallKillTask(param.ScanList[0], c.ClientIP())
			// 使用锁保护响应写入，确保并发安全
			globalMutex.Lock()
			defer globalMutex.Unlock()
			if err != nil {
				c.JSON(http.StatusOK, errno.ErrCallTask.WithData(map[string]string{"file": param.ScanList[0], "result": string(body)}))
				return
			}
			c.JSON(http.StatusOK, errno.OK.WithData(map[string]string{"file": param.ScanList[0], "result": string(body)}))
		case "HuoRong":
			body, err := proxy.CallKillTask(param.ScanList, c.ClientIP())
			// 使用锁保护响应写入，确保并发安全
			globalMutex.Lock()
			defer globalMutex.Unlock()
			if err != nil {
				c.JSON(http.StatusOK, errno.ErrCallTask.WithData(err.Error()))
				return
			}
			// 将 body 转为 JSON 格式
			var jsonData map[string]interface{} // 定义一个 map 来存储解析后的 JSON 数据
			_ = json.Unmarshal(body, &jsonData)
			// 返回 JSON 数据
			c.JSON(http.StatusOK, jsonData)
		default:
			c.JSON(http.StatusOK, errno.ErrSecurity)
		}
	}
}
